package com.luobr.backend.service.impl;

import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.luobr.backend.common.ResponseCode;
import com.luobr.backend.constant.UserConstant;
import com.luobr.backend.exception.BusinessException;
import com.luobr.backend.exception.ThrowUtils;
import com.luobr.backend.model.dto.space.SpaceAddRequest;
import com.luobr.backend.model.dto.space.SpaceQueryRequest;
import com.luobr.backend.model.entity.Space;
import com.luobr.backend.model.entity.SpaceUser;
import com.luobr.backend.model.enums.SpaceLevelEnum;
import com.luobr.backend.model.enums.SpaceTypeEnum;
import com.luobr.backend.model.enums.SpaceUserRoleEnum;
import com.luobr.backend.model.vo.user.UserLoginVO;
import com.luobr.backend.service.SpaceService;
import com.luobr.backend.mapper.SpaceMapper;
import com.luobr.backend.service.SpaceUserService;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

import javax.annotation.Resource;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author 罗念笙
 * @description 针对表【space(空间)】的数据库操作Service实现
 * @createDate 2025-03-11 14:55:44
 */
@Service
public class SpaceServiceImpl extends ServiceImpl<SpaceMapper, Space> implements SpaceService {

    @Resource
    @Lazy
    private SpaceUserService spaceUserService;
    @Resource
    private TransactionTemplate transactionTemplate;

    // 存储锁对象
    Map<Long, Object> lockMap = new ConcurrentHashMap<>();

    @Override
    public long addSpace(SpaceAddRequest spaceAddRequest, UserLoginVO loginUser) {
        // 将实体类和 DTO 进行转换
        Space space = SpaceAddRequest.dtoToObj(spaceAddRequest);
        // 权限校验
        if (SpaceLevelEnum.COMMON.getValue() != space.getSpaceLevel() && !loginUser.getUserRole().equals(UserConstant.USER_ROLE.ADMIN)) {
            throw new BusinessException(ResponseCode.NO_AUTH_ERROR, "无权限创建该级别的空间");
        }
        // 设置默认值
        space.setSpaceName(StrUtil.blankToDefault(space.getSpaceName(), "默认空间"));
        space.setSpaceLevel(Optional.ofNullable(space.getSpaceLevel()).orElse(SpaceLevelEnum.COMMON.getValue()));
        space.setSpaceType(Optional.ofNullable(space.getSpaceType()).orElse(SpaceTypeEnum.PRIVATE.getValue()));
        space.setTotalCount(0L);
        space.setTotalSize(0L);
        // 填充数据
        fillSpaceBySpaceLevel(space);
        // 数据校验
        validSpace(space);
        // 设置用户id
        Long userId = loginUser.getId();
        space.setUserId(userId);

//        // 加锁 + 事务的方法来创建唯一的私有空间
//        String lock = String.valueOf(userId).intern();
//        synchronized (lock) {
//            Long newSpaceId = transactionTemplate.execute(status -> {
//                // 通过用户id来判断用户是否已经创建了私有空间
//                boolean exists = this.lambdaQuery().eq(Space::getUserId, userId).exists();
//                ThrowUtils.throwIf(exists, ResponseCode.OPERATION_ERROR, "每个用户仅能有一个私有空间");
//                // 保存数据库
//                boolean result = this.save(space);
//                ThrowUtils.throwIf(!result, ResponseCode.OPERATION_ERROR);
//                // 返回新写入的数据 id
//                return space.getId();
//            });
//            // 返回结果是包装类
//            return Optional.ofNullable(newSpaceId).orElse(-1L);
//        }

        Object lock = lockMap.computeIfAbsent(userId, key -> new Object());
        synchronized (lock) {
            try {
                Long newSpaceId = transactionTemplate.execute(status -> {
                    // 通过用户id来判断用户是否已经创建了私有空间
                    boolean exists = this.lambdaQuery().eq(Space::getUserId, userId).eq(Space::getSpaceType,space.getSpaceType()).exists();
                    ThrowUtils.throwIf(exists, ResponseCode.OPERATION_ERROR, "每个用户仅能创建一种类型空间");
                    // 保存数据库
                    boolean result = this.save(space);
                    ThrowUtils.throwIf(!result, ResponseCode.OPERATION_ERROR);

                    // 如果是团队空间，关联新增团队成员记录
                    if (SpaceTypeEnum.TEAM.getValue() == spaceAddRequest.getSpaceType()) {
                        SpaceUser spaceUser = new SpaceUser();
                        spaceUser.setSpaceId(space.getId());
                        spaceUser.setUserId(userId);
                        spaceUser.setSpaceUserRole(SpaceUserRoleEnum.ADMIN.getValue());
                        result = spaceUserService.save(spaceUser);
                        ThrowUtils.throwIf(!result, ResponseCode.OPERATION_ERROR, "创建团队成员记录失败");
                    }

                    // 返回新写入的数据 id
                    return space.getId();
                });
                // 返回结果是包装类
                return Optional.ofNullable(newSpaceId).orElse(-1L);
            } finally {
                // 防止内存泄漏
                lockMap.remove(userId);
            }
        }
    }

    @Override
    public QueryWrapper<Space> getQueryWrapper(SpaceQueryRequest spaceQueryRequest) {
        QueryWrapper<Space> spaceQueryWrapper = new QueryWrapper<>();
        if (spaceQueryRequest == null) {
            return spaceQueryWrapper;
        }
        // 从对象中取值
        Long id = spaceQueryRequest.getId();
        Long userId = spaceQueryRequest.getUserId();
        String spaceName = spaceQueryRequest.getSpaceName();
        Integer spaceLevel = spaceQueryRequest.getSpaceLevel();
        String sortField = spaceQueryRequest.getSortField();
        String sortOrder = spaceQueryRequest.getSortOrder();
        Integer spaceType = spaceQueryRequest.getSpaceType();


        // 普通查询条件
        spaceQueryWrapper.eq(ObjUtil.isNotEmpty(id), "id", id);
        spaceQueryWrapper.eq(ObjUtil.isNotEmpty(userId), "userId", userId);
        spaceQueryWrapper.eq(ObjUtil.isNotEmpty(spaceLevel), "spaceLevel", spaceLevel);
        spaceQueryWrapper.eq(ObjUtil.isNotEmpty(spaceType), "spaceType", spaceType);
        spaceQueryWrapper.like(StrUtil.isNotBlank(spaceName), "spaceName", spaceName);
        // 排序条件
        spaceQueryWrapper.orderBy(StrUtil.isNotBlank("sortOrder"), sortOrder.equals("ascend"), sortField);
        return spaceQueryWrapper;
    }

    @Override
    public void validSpace(Space space) {
        ThrowUtils.throwIf(ObjUtil.isNull(space), ResponseCode.PARAMS_ERROR);
        // 从对象中取值
        String spaceName = space.getSpaceName();
        Integer spaceLevel = space.getSpaceLevel();
        Integer spaceType = space.getSpaceType();
        // 校验参数
        Long id = space.getId();
        if (ObjUtil.isNotNull(id) && id > 0) {
            // 如果是更新空间时，需要判断数据库中是否存在该空间
            Space spaceDB = getById(id);
            ThrowUtils.throwIf(ObjUtil.isNull(spaceDB), ResponseCode.NOT_FOUND_ERROR, "更新的源空间数据不存在！");
        } else {
            // 如果是创建空间时，校验名称和空间级别是否为空
            ThrowUtils.throwIf(StrUtil.isBlank(spaceName) || ObjUtil.isNull(spaceLevel) || ObjUtil.isNull(spaceType) ,
                    ResponseCode.PARAMS_ERROR, "空间名称、空间级别或者空间类型不能为空！");
        }
        // 获取空间等级枚举值
        SpaceLevelEnum spaceLevelEnum = SpaceLevelEnum.getEnumByValue(spaceLevel);
        // 获取空间类型枚举值
        SpaceTypeEnum spaceTypeEnum = SpaceTypeEnum.getEnumByValue(spaceType);
        // 校验空间信息是否符合要求
        ThrowUtils.throwIf(spaceLevel != null && spaceLevelEnum == null,
                ResponseCode.PARAMS_ERROR, "空间级别不存在！");
        ThrowUtils.throwIf(StrUtil.isNotBlank(spaceName) && spaceName.length() > 30,
                ResponseCode.PARAMS_ERROR, "空间名称过长！");
        ThrowUtils.throwIf(spaceType != null && spaceTypeEnum == null,
                ResponseCode.PARAMS_ERROR, "空间类型不存在！");
    }

    @Override
    public void fillSpaceBySpaceLevel(Space space) {
        // 根据空间级别，自动填充大小和数量
        SpaceLevelEnum spaceLevelEnum = SpaceLevelEnum.getEnumByValue(space.getSpaceLevel());
        if (spaceLevelEnum != null) {
            if (ObjUtil.isNull(space.getMaxSize())) {
                space.setMaxSize(spaceLevelEnum.getMaxSize());
            }
            if (ObjUtil.isNull(space.getMaxCount())) {
                space.setMaxCount(spaceLevelEnum.getMaxCount());
            }
        }
    }
}